<?php
/**
 * Copyright 2011  SURFfoundation
 * 
 * This file is part of ESCAPE.
 * 
 * ESCAPE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ESCAPE is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ESCAPE.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For more information:
 * http://escapesurf.wordpress.com/
 * http://www.surffoundation.nl/
 * 
 * Contact: d.vierkant@utwente.nl
 * 
 * @license http://www.gnu.org/licenses/gpl.html GNU GPLv3
 */
?>
<?php
/**
 * Create ORE aggregated resource
 * 
 * Create an ORE aggregated resource and add extracted metadata.
 */
class escape_repositoryui_rpc_CreateOreAggregatedResource extends escape_repositoryui_RpcHandler
{
	public function handleRequest()
	{
		$aggregationUri = $_REQUEST['aggregationUri'];
		$typeUri = $_REQUEST['typeUri'];
		$externalUri = trim($_REQUEST['externalUri']);
		$titleUri = trim($_REQUEST['titleUri']);
		$titleValue = $_REQUEST['titleValue'];
		$metadata = json_decode($_REQUEST['metadata'], true);
		
		// fetch the aggregation
		$aggregation = $this->repository->getOreAggregationByUri($aggregationUri);
		if($aggregation === null)
		{
			throw new escape_repositoryui_exception_Exception('Failed to fetch the specified aggregation');
		}
		
		// only administrators, editors and owners are allowed to create aggregated resources
		$user = $this->repositoryUi->user;
		if($user === null || !($user->hasSystemRole(escape_repository_User::$role_administrator) || $aggregation->hasEditor($user->getUri()) || $aggregation->hasOwner($user->getUri())))
		{
			throw new escape_repositoryui_exception_Rpc("Not authorized");
		}

		// throw an exception if objects with the same URI exist in this aggregation
		if($this->getAggregatedResourceUriHavingExternalUri($aggregation, $externalUri) !== null)
		{
			throw new escape_repositoryui_exception_Rpc("An object with the URL '" . $externalUri . "' already exists in this aggregation.");
		}
		
		// parse [[new::...]] object values and relatedObjectRdfXml
		foreach($metadata as $metadataRowIdx => $metadataRow)
		{
			$object = $metadataRow['object'];
			
			// check if the object contains a [[new:...]] type reference
			if(preg_match('/^\\[\\[new::(.+)\\]\\]$/', $object, $matches))
			{
				$relatedObjectRdfType = $matches[1];
				
				// parse the RDF/XML
				$relatedObjectRdfResource = new simplerdf_RdfResource($metadataRow['relatedObjectRdfXml']);

				// string any RDF types specified in the RDF resource
				$relatedObjectRdfResource->setRdfType(array());

				// check if an aggregated resource exists with the same external URI as the subject of the related object
				$existingAggregatedResourceUri = $this->getAggregatedResourceUriHavingExternalUri($aggregation, $relatedObjectRdfResource->getSubject());
				if($existingAggregatedResourceUri !== null)
				{
					// link to the existing object instead
					//TODO: this might lead to unexpected behaviour from the end user's point of view, it is an unlikey situation however since the user will probably choose the matched relation with the existing object
					$metadataRow['object'] = $existingAggregatedResourceUri;
				}
				else
				{
					// create a new aggregated resource
					
					// use the subject URI only if it's a URI (not a bnode)
					$relatedObjectExternalUri = null;
					if(simplerdf_Util::guessType($relatedObjectRdfResource->getSubject()) === 'uri')
					{
						$relatedObjectExternalUri = $relatedObjectRdfResource->getSubject();
					} 
					
					// create a new aggregated resource
					$aggregatedResource = $this->createAggregatedResource($aggregation, $user, $relatedObjectExternalUri, $relatedObjectRdfType, $relatedObjectRdfResource);
					
					// replace the object value with a reference to the related aggregated resource 
					$metadataRow['object'] = $aggregatedResource->getUri();
				}
			}
			
			$metadata[$metadataRowIdx] = $metadataRow;
		}
		
		// create an empty RDF resource for the new aggregated resource
		$rdfResource = simplerdf_RdfResource::createRdfResource('#');
		
		// set the RDF type
		$rdfResource->setRdfType($typeUri);
		
		// set the title, if available
		if($titleValue !== null && trim($titleValue) !== '')
		{
			$rdfResource->addStatement($titleUri, $titleValue);
		}
		
		// add additional metadata
		foreach($metadata as $metadataRow)
		{
			$predicate = $metadataRow['predicate'];
			$object = $metadataRow['object'];
			
			if($predicate === 'http://purl.utwente.nl/ns/escape-system.owl#externalUri')
			{
				// this is an external URI, it should replace the URL supplied by the user
				$externalUri = $object;
			}
			else
			{
				// add the statement to the additional metadata RDF resource
				$rdfResource->addStatement($predicate, $object);
			}
		}
		
		// create the aggregated resource
		$aggregatedResource = $this->createAggregatedResource($aggregation, $user, $externalUri, $typeUri, $rdfResource);
		
		// return the URI of the new aggregated resource in JSON format
		print json_encode($aggregatedResource->getUri());
	}
	
	/**
	 * Check if an aggregated resource with the external URI specified exists in the aggregation specified.
	 * @param escape_repository_OreAggregation $aggregation
	 * @param string $externalUri external URI
	 * @return boolean true if an aggregated resource with the external URI specified exists in the aggregation specified
	 */
	public function getAggregatedResourceUriHavingExternalUri($aggregation, $externalUri)
	{
		$aggregatedResourceUri = null;
		
		// check if other objects with the same URI exist in this aggregation
		if($externalUri !== null && $externalUri !== '' && simplerdf_Util::guessType($externalUri) === 'uri')
		{
			$externalUriMatches = $aggregation->getAggregatedResourceUrisHavingPredicateAndObject('http://purl.utwente.nl/ns/escape-system.owl#externalUri', $externalUri);

			if(count($externalUriMatches) > 0)
			{
				$aggregatedResourceUri = $externalUriMatches[0];
			}
		}
		
		return $aggregatedResourceUri;
	}
	
	/**
	 * Create an aggregated resource.
	 * In addition to creating the aggregated resource, created by, modified by and additional metadata statements are added to the new resource.  
	 * @param escape_repository_OreAggregation $aggregation aggregation
	 * @param escape_repository_USer $user user
	 * @param string $externalUri external URI
	 * @param string $typeUri RDF type URI
	 * @param simplerdf_RdfResource $additionalMetadataRdfResource additional metadata to add to the new resource
	 * @return escape_repository_OreAggregatedResource aggregated resource
	 * @throws escape_repositoryui_exception_Rpc an RPC exception is thrown if the aggregated resource can not be created 
	 */
	public function createAggregatedResource($aggregation, $user, $externalUri, $typeUri, $additionalMetadataRdfResource)
	{
		// create a new aggregated resource
		$aggregatedResource = $aggregation->createAggregatedResource();
		if($aggregatedResource === null)
		{
			throw new escape_repositoryui_exception_Rpc('Failed to create a new aggregated resource');
		}
		
		// add additional metadata
		$rdfResource = $aggregatedResource->getProperties();
		
		$predicates = $additionalMetadataRdfResource->getPredicates();
		foreach($predicates as $predicate)
		{
			//TODO: check if properties aren't system properties
			$objects = $additionalMetadataRdfResource->getObjects($predicate);
			$rdfResource->addStatement($predicate, $objects);
		}
		
		// set basic metadata
		if($externalUri !== null && $externalUri !== "")
		{
			$rdfResource->removeStatement('http://purl.utwente.nl/ns/escape-system.owl#externalUri');
			$rdfResource->addStatement('http://purl.utwente.nl/ns/escape-system.owl#externalUri', $externalUri);
		}
		$rdfResource->removeStatement('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
		$rdfResource->addStatement('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', $typeUri);
		$rdfResource->removeStatement('http://purl.utwente.nl/ns/escape-system.owl#createdBy');
		$rdfResource->addStatement('http://purl.utwente.nl/ns/escape-system.owl#createdBy', $user->getId());
		$rdfResource->removeStatement('http://purl.utwente.nl/ns/escape-system.owl#lastModifiedBy');
		$rdfResource->addStatement('http://purl.utwente.nl/ns/escape-system.owl#lastModifiedBy', $user->getId());
		
		// save the properties
		$aggregatedResource->setProperties($rdfResource);
		
		return $aggregatedResource;
	}
}
